# language: zh-CN
# Epic 12.2: 第三方服务集成
# 需求ID: REQ-012.2
# SRS需求: 系统应支持主流第三方服务集成，包括支付网关(Stripe/PayPal)、邮件服务(SendGrid/AWS SES)、短信服务、云存储(AWS S3/阿里云OSS)、社交媒体登录、推送通知等服务的无缝集成
# Feature ID: FT-012.2
# 关联Epic: EP-012 (云原生与集成)
# 优先级: 高
# 复杂度: 中等

# 用户故事:
# US-066: 作为开发者，我希望集成支付网关(Stripe/PayPal)，以便处理在线支付、订阅和退款
# US-067: 作为开发者，我希望集成邮件服务和短信服务，以便发送事务性邮件、通知和验证码
# US-068: 作为开发者，我希望集成云存储服务，以便存储和管理文件资源、图片和文档
# US-069: 作为开发者，我希望集成社交媒体登录和推送通知，以便提供便捷的用户认证和消息推送

# 验收标准:
# - 支持主流支付网关集成，包括支付、订阅、退款、Webhook处理
# - 支持邮件和短信服务集成，包括模板管理、批量发送、状态跟踪
# - 支持云存储服务集成，包括文件上传、下载、CDN加速
# - 支持社交媒体OAuth登录，包括微信、QQ、GitHub、Google等
# - 支持推送通知服务，包括APP推送、浏览器推送
# - 提供统一的集成配置管理和监控机制
# - 支持集成服务的健康检查和故障转移
# - 提供详细的集成日志和错误处理

功能: 第三方集成
  作为应用开发者
  我希望系统支持第三方服务集成
  以便扩展应用功能和提升用户体验

  背景:
    假设我是一个应用开发者
    并且我需要集成各种第三方服务
    并且我需要确保集成的安全性和可靠性
    并且我需要支持灵活的配置管理

  # 用户故事: US-066 - 集成支付网关处理在线支付和订阅
  场景: 支付网关集成
    假设我需要集成支付服务
    当我配置支付网关时:
      """
      @integration({
        provider: 'stripe',
        type: 'payment',
        config: {
          publicKey: env('STRIPE_PUBLIC_KEY'),
          secretKey: env('STRIPE_SECRET_KEY'),
          webhookSecret: env('STRIPE_WEBHOOK_SECRET'),
          apiVersion: '2023-10-16'
        },
        features: {
          payments: true,
          subscriptions: true,
          refunds: true,
          webhooks: true,
          connect: false
        }
      })
      
      entity Payment {
        id: string @primary
        amount: number @required
        currency: string @required @default('USD')
        status: PaymentStatus @required
        
        // Stripe集成字段
        stripePaymentIntentId: string @external('stripe.payment_intent.id')
        stripeCustomerId: string @external('stripe.customer.id')
        
        // 关联
        orderId: string @foreign_key('Order')
        customerId: string @foreign_key('Customer')
        
        createdAt: datetime @auto_now_add
        updatedAt: datetime @auto_now
      }
      
      enum PaymentStatus {
        PENDING = 'pending'
        PROCESSING = 'processing'
        SUCCEEDED = 'succeeded'
        FAILED = 'failed'
        CANCELED = 'canceled'
        REFUNDED = 'refunded'
      }
      
      // 支付服务
      service PaymentService {
        @stripe_integration
        async createPayment(data: CreatePaymentRequest): Promise<Payment> {
          const paymentIntent = await stripe.paymentIntents.create({
            amount: data.amount * 100, // 转换为分
            currency: data.currency,
            customer: data.customerId,
            metadata: {
              orderId: data.orderId
            }
          });
          
          return Payment.create({
            ...data,
            stripePaymentIntentId: paymentIntent.id,
            status: PaymentStatus.PENDING
          });
        }
        
        @stripe_webhook
        async handleWebhook(event: StripeWebhookEvent): Promise<void> {
          switch (event.type) {
            case 'payment_intent.succeeded':
              await this.updatePaymentStatus(event.data.object.id, PaymentStatus.SUCCEEDED);
              break;
            case 'payment_intent.payment_failed':
              await this.updatePaymentStatus(event.data.object.id, PaymentStatus.FAILED);
              break;
          }
        }
      }
      """
    那么应该生成支付集成代码:
      """
      // 生成的Stripe客户端
      import Stripe from 'stripe';
      
      const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
        apiVersion: '2023-10-16',
        typescript: true
      });
      
      // 支付处理
      export class PaymentService {
        async createPayment(data: CreatePaymentRequest): Promise<Payment> {
          try {
            const paymentIntent = await stripe.paymentIntents.create({
              amount: Math.round(data.amount * 100),
              currency: data.currency.toLowerCase(),
              customer: data.stripeCustomerId,
              metadata: {
                orderId: data.orderId,
                customerId: data.customerId
              },
              automatic_payment_methods: {
                enabled: true
              }
            });
            
            const payment = await Payment.create({
              amount: data.amount,
              currency: data.currency,
              status: PaymentStatus.PENDING,
              stripePaymentIntentId: paymentIntent.id,
              stripeCustomerId: data.stripeCustomerId,
              orderId: data.orderId,
              customerId: data.customerId
            });
            
            return payment;
          } catch (error) {
            throw new PaymentError('Failed to create payment', error);
          }
        }
        
        async handleWebhook(rawBody: string, signature: string): Promise<void> {
          let event: Stripe.Event;
          
          try {
            event = stripe.webhooks.constructEvent(
              rawBody,
              signature,
              process.env.STRIPE_WEBHOOK_SECRET!
            );
          } catch (error) {
            throw new WebhookError('Invalid webhook signature', error);
          }
          
          switch (event.type) {
            case 'payment_intent.succeeded':
              await this.updatePaymentStatus(
                event.data.object.id,
                PaymentStatus.SUCCEEDED
              );
              break;
            case 'payment_intent.payment_failed':
              await this.updatePaymentStatus(
                event.data.object.id,
                PaymentStatus.FAILED
              );
              break;
          }
        }
      }
      """
    并且应该支持多种支付方式
    并且应该处理Webhook事件
    并且应该支持退款操作
    并且应该提供错误处理

  # 用户故事: US-067 - 集成邮件服务发送事务性邮件和营销邮件
  场景: 邮件服务集成
    假设我需要集成邮件发送服务
    当我配置邮件服务时:
      """
      @integration({
        provider: 'sendgrid',
        type: 'email',
        config: {
          apiKey: env('SENDGRID_API_KEY'),
          fromEmail: env('FROM_EMAIL'),
          fromName: env('FROM_NAME'),
          templates: {
            welcome: 'd-1234567890abcdef',
            resetPassword: 'd-abcdef1234567890',
            orderConfirmation: 'd-567890abcdef1234'
          }
        },
        features: {
          transactional: true,
          marketing: false,
          templates: true,
          tracking: true,
          analytics: true
        }
      })
      
      entity EmailLog {
        id: string @primary
        to: string @required
        from: string @required
        subject: string @required
        template: string @optional
        status: EmailStatus @required
        
        // SendGrid集成字段
        sendgridMessageId: string @external('sendgrid.message.id')
        
        // 追踪信息
        sentAt: datetime @optional
        deliveredAt: datetime @optional
        openedAt: datetime @optional
        clickedAt: datetime @optional
        
        // 错误信息
        errorMessage: string @optional
        
        createdAt: datetime @auto_now_add
        updatedAt: datetime @auto_now
      }
      
      enum EmailStatus {
        QUEUED = 'queued'
        SENT = 'sent'
        DELIVERED = 'delivered'
        OPENED = 'opened'
        CLICKED = 'clicked'
        BOUNCED = 'bounced'
        FAILED = 'failed'
      }
      
      service EmailService {
        @sendgrid_integration
        async sendWelcomeEmail(userId: string, email: string, name: string): Promise<EmailLog> {
          const templateData = {
            name: name,
            loginUrl: `${process.env.APP_URL}/login`
          };
          
          return this.sendTemplateEmail({
            to: email,
            template: 'welcome',
            data: templateData,
            userId: userId
          });
        }
        
        @sendgrid_integration
        async sendPasswordResetEmail(email: string, resetToken: string): Promise<EmailLog> {
          const templateData = {
            resetUrl: `${process.env.APP_URL}/reset-password?token=${resetToken}`,
            expiresIn: '1 hour'
          };
          
          return this.sendTemplateEmail({
            to: email,
            template: 'resetPassword',
            data: templateData
          });
        }
        
        @sendgrid_webhook
        async handleWebhook(events: SendGridWebhookEvent[]): Promise<void> {
          for (const event of events) {
            await this.updateEmailStatus(event.sg_message_id, event.event, event.timestamp);
          }
        }
      }
      """
    那么应该生成邮件集成代码:
      """
      import sgMail from '@sendgrid/mail';
      
      sgMail.setApiKey(process.env.SENDGRID_API_KEY!);
      
      export class EmailService {
        async sendTemplateEmail(options: SendTemplateEmailOptions): Promise<EmailLog> {
          try {
            const msg = {
              to: options.to,
              from: {
                email: process.env.FROM_EMAIL!,
                name: process.env.FROM_NAME!
              },
              templateId: this.getTemplateId(options.template),
              dynamicTemplateData: options.data,
              trackingSettings: {
                clickTracking: { enable: true },
                openTracking: { enable: true },
                subscriptionTracking: { enable: false }
              }
            };
            
            const [response] = await sgMail.send(msg);
            
            const emailLog = await EmailLog.create({
              to: options.to,
              from: msg.from.email,
              subject: `Template: ${options.template}`,
              template: options.template,
              status: EmailStatus.QUEUED,
              sendgridMessageId: response.headers['x-message-id'],
              sentAt: new Date()
            });
            
            return emailLog;
          } catch (error) {
            const emailLog = await EmailLog.create({
              to: options.to,
              from: process.env.FROM_EMAIL!,
              subject: `Template: ${options.template}`,
              template: options.template,
              status: EmailStatus.FAILED,
              errorMessage: error.message
            });
            
            throw new EmailError('Failed to send email', error);
          }
        }
        
        async handleWebhook(events: SendGridWebhookEvent[]): Promise<void> {
          for (const event of events) {
            const status = this.mapSendGridEventToStatus(event.event);
            
            await EmailLog.update(
              { sendgridMessageId: event.sg_message_id },
              {
                status,
                ...(event.event === 'delivered' && { deliveredAt: new Date(event.timestamp * 1000) }),
                ...(event.event === 'open' && { openedAt: new Date(event.timestamp * 1000) }),
                ...(event.event === 'click' && { clickedAt: new Date(event.timestamp * 1000) })
              }
            );
          }
        }
        
        private getTemplateId(template: string): string {
          const templates = {
            welcome: 'd-1234567890abcdef',
            resetPassword: 'd-abcdef1234567890',
            orderConfirmation: 'd-567890abcdef1234'
          };
          return templates[template] || templates.welcome;
        }
        
        private mapSendGridEventToStatus(event: string): EmailStatus {
          const mapping = {
            'processed': EmailStatus.SENT,
            'delivered': EmailStatus.DELIVERED,
            'open': EmailStatus.OPENED,
            'click': EmailStatus.CLICKED,
            'bounce': EmailStatus.BOUNCED,
            'dropped': EmailStatus.FAILED
          };
          return mapping[event] || EmailStatus.QUEUED;
        }
      }
      """
    并且应该支持模板邮件
    并且应该追踪邮件状态
    并且应该处理发送失败
    并且应该提供分析数据

  # 用户故事: US-068 - 集成云存储服务存储和管理文件资源
  场景: 云存储集成
    假设我需要集成云存储服务
    当我配置云存储时:
      """
      @integration({
        provider: 'aws_s3',
        type: 'storage',
        config: {
          accessKeyId: env('AWS_ACCESS_KEY_ID'),
          secretAccessKey: env('AWS_SECRET_ACCESS_KEY'),
          region: env('AWS_REGION'),
          bucket: env('S3_BUCKET'),
          cdnDomain: env('CLOUDFRONT_DOMAIN')
        },
        features: {
          upload: true,
          download: true,
          delete: true,
          presignedUrls: true,
          multipart: true,
          versioning: true
        }
      })
      
      entity FileUpload {
        id: string @primary
        filename: string @required
        originalName: string @required
        mimeType: string @required
        size: number @required
        
        // S3集成字段
        s3Key: string @external('s3.object.key')
        s3Bucket: string @external('s3.bucket.name')
        s3ETag: string @external('s3.object.etag')
        s3VersionId: string @external('s3.object.version_id') @optional
        
        // URL信息
        publicUrl: string @computed
        cdnUrl: string @computed
        
        // 元数据
        metadata: json @optional
        tags: json @optional
        
        // 关联
        uploadedBy: string @foreign_key('User')
        
        createdAt: datetime @auto_now_add
        updatedAt: datetime @auto_now
      }
      
      service FileService {
        @s3_integration
        async uploadFile(file: Express.Multer.File, userId: string): Promise<FileUpload> {
          const key = this.generateS3Key(file.originalname);
          
          const uploadParams = {
            Bucket: process.env.S3_BUCKET!,
            Key: key,
            Body: file.buffer,
            ContentType: file.mimetype,
            Metadata: {
              'uploaded-by': userId,
              'original-name': file.originalname
            },
            TagSet: [
              { Key: 'Environment', Value: process.env.NODE_ENV! },
              { Key: 'UploadedBy', Value: userId }
            ]
          };
          
          const result = await s3.upload(uploadParams).promise();
          
          return FileUpload.create({
            filename: key,
            originalName: file.originalname,
            mimeType: file.mimetype,
            size: file.size,
            s3Key: key,
            s3Bucket: process.env.S3_BUCKET!,
            s3ETag: result.ETag,
            uploadedBy: userId
          });
        }
        
        @s3_integration
        async generatePresignedUrl(fileId: string, expiresIn: number = 3600): Promise<string> {
          const file = await FileUpload.findById(fileId);
          if (!file) throw new FileNotFoundError('File not found');
          
          const params = {
            Bucket: file.s3Bucket,
            Key: file.s3Key,
            Expires: expiresIn
          };
          
          return s3.getSignedUrl('getObject', params);
        }
        
        @s3_integration
        async deleteFile(fileId: string): Promise<void> {
          const file = await FileUpload.findById(fileId);
          if (!file) throw new FileNotFoundError('File not found');
          
          await s3.deleteObject({
            Bucket: file.s3Bucket,
            Key: file.s3Key
          }).promise();
          
          await FileUpload.delete({ id: fileId });
        }
      }
      """
    那么应该生成存储集成代码:
      """
      import AWS from 'aws-sdk';
      import { v4 as uuidv4 } from 'uuid';
      import path from 'path';
      
      const s3 = new AWS.S3({
        accessKeyId: process.env.AWS_ACCESS_KEY_ID,
        secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
        region: process.env.AWS_REGION
      });
      
      export class FileService {
        async uploadFile(file: Express.Multer.File, userId: string): Promise<FileUpload> {
          try {
            const key = this.generateS3Key(file.originalname);
            
            const uploadParams: AWS.S3.PutObjectRequest = {
              Bucket: process.env.S3_BUCKET!,
              Key: key,
              Body: file.buffer,
              ContentType: file.mimetype,
              ContentDisposition: `attachment; filename="${file.originalname}"`,
              Metadata: {
                'uploaded-by': userId,
                'original-name': Buffer.from(file.originalname, 'utf8').toString('base64'),
                'upload-timestamp': Date.now().toString()
              },
              TagSet: [
                { Key: 'Environment', Value: process.env.NODE_ENV! },
                { Key: 'UploadedBy', Value: userId },
                { Key: 'FileType', Value: file.mimetype.split('/')[0] }
              ]
            };
            
            const result = await s3.upload(uploadParams).promise();
            
            const fileUpload = await FileUpload.create({
              filename: key,
              originalName: file.originalname,
              mimeType: file.mimetype,
              size: file.size,
              s3Key: key,
              s3Bucket: process.env.S3_BUCKET!,
              s3ETag: result.ETag?.replace(/"/g, ''),
              s3VersionId: result.VersionId,
              uploadedBy: userId,
              metadata: {
                contentLength: file.size,
                lastModified: new Date().toISOString()
              }
            });
            
            return fileUpload;
          } catch (error) {
            throw new FileUploadError('Failed to upload file to S3', error);
          }
        }
        
        async generatePresignedUrl(fileId: string, expiresIn: number = 3600): Promise<string> {
          const file = await FileUpload.findById(fileId);
          if (!file) {
            throw new FileNotFoundError(`File with ID ${fileId} not found`);
          }
          
          const params = {
            Bucket: file.s3Bucket,
            Key: file.s3Key,
            Expires: expiresIn,
            ResponseContentDisposition: `attachment; filename="${file.originalName}"`
          };
          
          return s3.getSignedUrl('getObject', params);
        }
        
        async getFileStream(fileId: string): Promise<NodeJS.ReadableStream> {
          const file = await FileUpload.findById(fileId);
          if (!file) {
            throw new FileNotFoundError(`File with ID ${fileId} not found`);
          }
          
          const params = {
            Bucket: file.s3Bucket,
            Key: file.s3Key
          };
          
          return s3.getObject(params).createReadStream();
        }
        
        private generateS3Key(originalName: string): string {
          const ext = path.extname(originalName);
          const timestamp = Date.now();
          const uuid = uuidv4();
          return `uploads/${timestamp}/${uuid}${ext}`;
        }
      }
      """
    并且应该支持大文件上传
    并且应该生成预签名URL
    并且应该支持文件版本管理
    并且应该提供CDN加速

  # 用户故事: US-070 - 集成短信服务发送验证码和通知
  场景: 短信服务集成
    假设我需要集成短信发送服务
    当我配置短信服务时:
      """
      @integration({
        provider: 'twilio',
        type: 'sms',
        config: {
          accountSid: env('TWILIO_ACCOUNT_SID'),
          authToken: env('TWILIO_AUTH_TOKEN'),
          fromNumber: env('TWILIO_FROM_NUMBER'),
          messagingServiceSid: env('TWILIO_MESSAGING_SERVICE_SID')
        },
        features: {
          sms: true,
          mms: false,
          voice: false,
          verify: true,
          lookup: true
        }
      })
      
      entity SmsLog {
        id: string @primary
        to: string @required
        from: string @required
        message: string @required
        status: SmsStatus @required
        
        // Twilio集成字段
        twilioSid: string @external('twilio.message.sid')
        twilioStatus: string @external('twilio.message.status')
        
        // 追踪信息
        sentAt: datetime @optional
        deliveredAt: datetime @optional
        
        // 错误信息
        errorCode: string @optional
        errorMessage: string @optional
        
        // 成本信息
        price: number @optional
        priceUnit: string @optional
        
        createdAt: datetime @auto_now_add
        updatedAt: datetime @auto_now
      }
      
      enum SmsStatus {
        QUEUED = 'queued'
        SENT = 'sent'
        DELIVERED = 'delivered'
        FAILED = 'failed'
        UNDELIVERED = 'undelivered'
      }
      
      service SmsService {
        @twilio_integration
        async sendVerificationCode(phoneNumber: string): Promise<SmsLog> {
          const code = this.generateVerificationCode();
          const message = `Your verification code is: ${code}. Valid for 10 minutes.`;
          
          return this.sendSms(phoneNumber, message, {
            type: 'verification',
            code: code,
            expiresAt: new Date(Date.now() + 10 * 60 * 1000) // 10分钟后过期
          });
        }
        
        @twilio_integration
        async sendOrderNotification(phoneNumber: string, orderNumber: string): Promise<SmsLog> {
          const message = `Your order #${orderNumber} has been confirmed and is being processed.`;
          
          return this.sendSms(phoneNumber, message, {
            type: 'notification',
            orderNumber: orderNumber
          });
        }
        
        @twilio_webhook
        async handleWebhook(event: TwilioWebhookEvent): Promise<void> {
          await this.updateSmsStatus(
            event.MessageSid,
            event.MessageStatus,
            {
              errorCode: event.ErrorCode,
              errorMessage: event.ErrorMessage,
              price: event.Price,
              priceUnit: event.PriceUnit
            }
          );
        }
      }
      """
    那么应该生成短信集成代码:
      """
      import twilio from 'twilio';
      
      const client = twilio(
        process.env.TWILIO_ACCOUNT_SID!,
        process.env.TWILIO_AUTH_TOKEN!
      );
      
      export class SmsService {
        async sendSms(to: string, message: string, metadata?: any): Promise<SmsLog> {
          try {
            // 验证手机号格式
            const phoneNumber = this.formatPhoneNumber(to);
            
            const messageOptions = {
              body: message,
              to: phoneNumber,
              from: process.env.TWILIO_FROM_NUMBER,
              ...(process.env.TWILIO_MESSAGING_SERVICE_SID && {
                messagingServiceSid: process.env.TWILIO_MESSAGING_SERVICE_SID
              }),
              statusCallback: `${process.env.APP_URL}/webhooks/twilio/sms`,
              maxPrice: 0.05 // 最大价格限制
            };
            
            const twilioMessage = await client.messages.create(messageOptions);
            
            const smsLog = await SmsLog.create({
              to: phoneNumber,
              from: messageOptions.from,
              message: message,
              status: this.mapTwilioStatusToSmsStatus(twilioMessage.status),
              twilioSid: twilioMessage.sid,
              twilioStatus: twilioMessage.status,
              sentAt: new Date(),
              metadata: metadata
            });
            
            return smsLog;
          } catch (error) {
            const smsLog = await SmsLog.create({
              to: to,
              from: process.env.TWILIO_FROM_NUMBER!,
              message: message,
              status: SmsStatus.FAILED,
              errorMessage: error.message,
              metadata: metadata
            });
            
            throw new SmsError('Failed to send SMS', error);
          }
        }
        
        async verifyPhoneNumber(phoneNumber: string): Promise<boolean> {
          try {
            const lookup = await client.lookups.v1.phoneNumbers(phoneNumber).fetch();
            return lookup.phoneNumber !== null;
          } catch (error) {
            return false;
          }
        }
        
        async handleWebhook(body: TwilioWebhookEvent): Promise<void> {
          const status = this.mapTwilioStatusToSmsStatus(body.MessageStatus);
          
          await SmsLog.update(
            { twilioSid: body.MessageSid },
            {
              status,
              twilioStatus: body.MessageStatus,
              ...(body.MessageStatus === 'delivered' && {
                deliveredAt: new Date()
              }),
              ...(body.ErrorCode && {
                errorCode: body.ErrorCode,
                errorMessage: body.ErrorMessage
              }),
              ...(body.Price && {
                price: parseFloat(body.Price),
                priceUnit: body.PriceUnit
              })
            }
          );
        }
        
        private generateVerificationCode(): string {
          return Math.floor(100000 + Math.random() * 900000).toString();
        }
        
        private formatPhoneNumber(phoneNumber: string): string {
          // 移除所有非数字字符
          const cleaned = phoneNumber.replace(/\D/g, '');
          
          // 如果是中国手机号，添加+86前缀
          if (cleaned.length === 11 && cleaned.startsWith('1')) {
            return `+86${cleaned}`;
          }
          
          // 如果已经有国家代码，直接返回
          if (cleaned.length > 11) {
            return `+${cleaned}`;
          }
          
          throw new InvalidPhoneNumberError('Invalid phone number format');
        }
        
        private mapTwilioStatusToSmsStatus(twilioStatus: string): SmsStatus {
          const mapping = {
            'queued': SmsStatus.QUEUED,
            'sent': SmsStatus.SENT,
            'delivered': SmsStatus.DELIVERED,
            'failed': SmsStatus.FAILED,
            'undelivered': SmsStatus.UNDELIVERED
          };
          return mapping[twilioStatus] || SmsStatus.QUEUED;
        }
      }
      """
    并且应该支持验证码发送
    并且应该验证手机号格式
    并且应该追踪发送状态
    并且应该控制发送成本

  # 用户故事: US-069 - 集成社交媒体登录提供便捷的用户认证方式
  场景: 社交媒体集成
    假设我需要集成社交媒体登录
    当我配置OAuth集成时:
      """
      @integration({
        provider: 'google_oauth',
        type: 'authentication',
        config: {
          clientId: env('GOOGLE_CLIENT_ID'),
          clientSecret: env('GOOGLE_CLIENT_SECRET'),
          redirectUri: env('GOOGLE_REDIRECT_URI'),
          scopes: ['openid', 'profile', 'email']
        },
        features: {
          login: true,
          signup: true,
          profileSync: true,
          tokenRefresh: true
        }
      })
      
      @integration({
        provider: 'github_oauth',
        type: 'authentication',
        config: {
          clientId: env('GITHUB_CLIENT_ID'),
          clientSecret: env('GITHUB_CLIENT_SECRET'),
          redirectUri: env('GITHUB_REDIRECT_URI'),
          scopes: ['user:email']
        }
      })
      
      entity SocialAccount {
        id: string @primary
        provider: SocialProvider @required
        providerId: string @required
        
        // 用户信息
        email: string @required
        name: string @required
        avatar: string @optional
        
        // OAuth信息
        accessToken: string @encrypted
        refreshToken: string @encrypted @optional
        tokenExpiresAt: datetime @optional
        
        // 权限范围
        scopes: string[] @required
        
        // 关联
        userId: string @foreign_key('User')
        
        createdAt: datetime @auto_now_add
        updatedAt: datetime @auto_now
        
        @@unique([provider, providerId])
        @@unique([provider, userId])
      }
      
      enum SocialProvider {
        GOOGLE = 'google'
        GITHUB = 'github'
        FACEBOOK = 'facebook'
        TWITTER = 'twitter'
        LINKEDIN = 'linkedin'
      }
      
      service AuthService {
        @oauth_integration
        async handleGoogleCallback(code: string): Promise<{ user: User, token: string }> {
          const tokenResponse = await this.exchangeCodeForToken('google', code);
          const userInfo = await this.fetchGoogleUserInfo(tokenResponse.access_token);
          
          let user = await User.findOne({ email: userInfo.email });
          
          if (!user) {
            user = await User.create({
              email: userInfo.email,
              name: userInfo.name,
              avatar: userInfo.picture,
              emailVerified: true // Google账号默认已验证
            });
          }
          
          await SocialAccount.upsert({
            provider: SocialProvider.GOOGLE,
            providerId: userInfo.sub,
            userId: user.id
          }, {
            email: userInfo.email,
            name: userInfo.name,
            avatar: userInfo.picture,
            accessToken: tokenResponse.access_token,
            refreshToken: tokenResponse.refresh_token,
            tokenExpiresAt: new Date(Date.now() + tokenResponse.expires_in * 1000),
            scopes: tokenResponse.scope.split(' ')
          });
          
          const jwtToken = this.generateJwtToken(user);
          return { user, token: jwtToken };
        }
        
        @oauth_integration
        async refreshSocialToken(socialAccountId: string): Promise<SocialAccount> {
          const account = await SocialAccount.findById(socialAccountId);
          if (!account || !account.refreshToken) {
            throw new TokenRefreshError('No refresh token available');
          }
          
          const tokenResponse = await this.refreshOAuthToken(account.provider, account.refreshToken);
          
          return SocialAccount.update({ id: socialAccountId }, {
            accessToken: tokenResponse.access_token,
            tokenExpiresAt: new Date(Date.now() + tokenResponse.expires_in * 1000)
          });
        }
      }
      """
    那么应该生成OAuth集成代码:
      """
      import { OAuth2Client } from 'google-auth-library';
      import axios from 'axios';
      
      const googleClient = new OAuth2Client(
        process.env.GOOGLE_CLIENT_ID,
        process.env.GOOGLE_CLIENT_SECRET,
        process.env.GOOGLE_REDIRECT_URI
      );
      
      export class AuthService {
        async getGoogleAuthUrl(): Promise<string> {
          return googleClient.generateAuthUrl({
            access_type: 'offline',
            scope: ['openid', 'profile', 'email'],
            prompt: 'consent'
          });
        }
        
        async handleGoogleCallback(code: string): Promise<{ user: User, token: string }> {
          try {
            const { tokens } = await googleClient.getToken(code);
            googleClient.setCredentials(tokens);
            
            const ticket = await googleClient.verifyIdToken({
              idToken: tokens.id_token!,
              audience: process.env.GOOGLE_CLIENT_ID
            });
            
            const payload = ticket.getPayload();
            if (!payload) {
              throw new AuthenticationError('Invalid Google token');
            }
            
            let user = await User.findOne({ email: payload.email });
            
            if (!user) {
              user = await User.create({
                email: payload.email!,
                name: payload.name!,
                avatar: payload.picture,
                emailVerified: payload.email_verified || false
              });
            }
            
            await SocialAccount.upsert(
              {
                provider: SocialProvider.GOOGLE,
                providerId: payload.sub,
                userId: user.id
              },
              {
                email: payload.email!,
                name: payload.name!,
                avatar: payload.picture,
                accessToken: tokens.access_token!,
                refreshToken: tokens.refresh_token,
                tokenExpiresAt: tokens.expiry_date ? new Date(tokens.expiry_date) : null,
                scopes: tokens.scope?.split(' ') || []
              }
            );
            
            const jwtToken = this.generateJwtToken(user);
            return { user, token: jwtToken };
          } catch (error) {
            throw new AuthenticationError('Google authentication failed', error);
          }
        }
        
        async getGitHubAuthUrl(): Promise<string> {
          const params = new URLSearchParams({
            client_id: process.env.GITHUB_CLIENT_ID!,
            redirect_uri: process.env.GITHUB_REDIRECT_URI!,
            scope: 'user:email',
            state: this.generateState()
          });
          
          return `https://github.com/login/oauth/authorize?${params.toString()}`;
        }
        
        async handleGitHubCallback(code: string, state: string): Promise<{ user: User, token: string }> {
          try {
            // 验证state参数
            if (!this.verifyState(state)) {
              throw new AuthenticationError('Invalid state parameter');
            }
            
            // 交换访问令牌
            const tokenResponse = await axios.post('https://github.com/login/oauth/access_token', {
              client_id: process.env.GITHUB_CLIENT_ID,
              client_secret: process.env.GITHUB_CLIENT_SECRET,
              code: code
            }, {
              headers: { 'Accept': 'application/json' }
            });
            
            const accessToken = tokenResponse.data.access_token;
            
            // 获取用户信息
            const userResponse = await axios.get('https://api.github.com/user', {
              headers: { 'Authorization': `token ${accessToken}` }
            });
            
            const emailResponse = await axios.get('https://api.github.com/user/emails', {
              headers: { 'Authorization': `token ${accessToken}` }
            });
            
            const primaryEmail = emailResponse.data.find((email: any) => email.primary);
            
            let user = await User.findOne({ email: primaryEmail.email });
            
            if (!user) {
              user = await User.create({
                email: primaryEmail.email,
                name: userResponse.data.name || userResponse.data.login,
                avatar: userResponse.data.avatar_url,
                emailVerified: primaryEmail.verified
              });
            }
            
            await SocialAccount.upsert(
              {
                provider: SocialProvider.GITHUB,
                providerId: userResponse.data.id.toString(),
                userId: user.id
              },
              {
                email: primaryEmail.email,
                name: userResponse.data.name || userResponse.data.login,
                avatar: userResponse.data.avatar_url,
                accessToken: accessToken,
                scopes: tokenResponse.data.scope?.split(',') || []
              }
            );
            
            const jwtToken = this.generateJwtToken(user);
            return { user, token: jwtToken };
          } catch (error) {
            throw new AuthenticationError('GitHub authentication failed', error);
          }
        }
        
        private generateState(): string {
          return Buffer.from(JSON.stringify({
            timestamp: Date.now(),
            random: Math.random().toString(36)
          })).toString('base64');
        }
        
        private verifyState(state: string): boolean {
          try {
            const decoded = JSON.parse(Buffer.from(state, 'base64').toString());
            const age = Date.now() - decoded.timestamp;
            return age < 10 * 60 * 1000; // 10分钟内有效
          } catch {
            return false;
          }
        }
      }
      """
    并且应该支持多种OAuth提供商
    并且应该处理令牌刷新
    并且应该同步用户资料
    并且应该提供安全验证

  # 用户故事: US-071 - 统一管理第三方集成配置和监控
  场景: 集成配置管理
    假设我需要统一管理集成配置
    当我配置集成管理时:
      """
      @integrationManager({
        configSource: 'environment', // environment, database, vault
        encryption: {
          enabled: true,
          algorithm: 'AES-256-GCM',
          keyRotation: true
        },
        monitoring: {
          healthChecks: true,
          metrics: true,
          alerts: true
        },
        rateLimiting: {
          enabled: true,
          defaultLimits: {
            requests: 1000,
            window: '1h'
          }
        }
      })
      
      entity Integration {
        id: string @primary
        name: string @required @unique
        provider: string @required
        type: IntegrationType @required
        status: IntegrationStatus @required
        
        // 配置信息
        config: json @encrypted
        features: string[] @required
        
        // 监控信息
        healthStatus: HealthStatus @required
        lastHealthCheck: datetime @optional
        
        // 使用统计
        requestCount: number @default(0)
        errorCount: number @default(0)
        lastUsed: datetime @optional
        
        // 限制配置
        rateLimits: json @optional
        
        createdAt: datetime @auto_now_add
        updatedAt: datetime @auto_now
      }
      
      enum IntegrationType {
        PAYMENT = 'payment'
        EMAIL = 'email'
        SMS = 'sms'
        STORAGE = 'storage'
        AUTHENTICATION = 'authentication'
        ANALYTICS = 'analytics'
        MONITORING = 'monitoring'
      }
      
      enum IntegrationStatus {
        ACTIVE = 'active'
        INACTIVE = 'inactive'
        ERROR = 'error'
        MAINTENANCE = 'maintenance'
      }
      
      enum HealthStatus {
        HEALTHY = 'healthy'
        DEGRADED = 'degraded'
        UNHEALTHY = 'unhealthy'
        UNKNOWN = 'unknown'
      }
      
      service IntegrationService {
        async registerIntegration(config: IntegrationConfig): Promise<Integration> {
          const integration = await Integration.create({
            name: config.name,
            provider: config.provider,
            type: config.type,
            status: IntegrationStatus.INACTIVE,
            config: this.encryptConfig(config.config),
            features: config.features,
            healthStatus: HealthStatus.UNKNOWN,
            rateLimits: config.rateLimits
          });
          
          await this.performHealthCheck(integration.id);
          return integration;
        }
        
        async performHealthCheck(integrationId: string): Promise<HealthStatus> {
          const integration = await Integration.findById(integrationId);
          if (!integration) throw new IntegrationNotFoundError();
          
          try {
            const healthChecker = this.getHealthChecker(integration.provider);
            const status = await healthChecker.check(integration.config);
            
            await Integration.update({ id: integrationId }, {
              healthStatus: status,
              lastHealthCheck: new Date(),
              status: status === HealthStatus.HEALTHY ? IntegrationStatus.ACTIVE : IntegrationStatus.ERROR
            });
            
            return status;
          } catch (error) {
            await Integration.update({ id: integrationId }, {
              healthStatus: HealthStatus.UNHEALTHY,
              lastHealthCheck: new Date(),
              status: IntegrationStatus.ERROR
            });
            
            throw new HealthCheckError('Health check failed', error);
          }
        }
      }
      """
    那么应该提供统一的集成管理:
      """
      {
        "integrationManagement": {
          "registeredIntegrations": [
            {
              "id": "stripe_payment",
              "name": "Stripe Payment",
              "provider": "stripe",
              "type": "payment",
              "status": "active",
              "healthStatus": "healthy",
              "features": ["payments", "subscriptions", "refunds"],
              "metrics": {
                "requestCount": 15420,
                "errorCount": 23,
                "errorRate": 0.0015,
                "avgResponseTime": "245ms",
                "uptime": "99.85%"
              },
              "rateLimits": {
                "requests": 1000,
                "window": "1h",
                "remaining": 756
              }
            },
            {
              "id": "sendgrid_email",
              "name": "SendGrid Email",
              "provider": "sendgrid",
              "type": "email",
              "status": "active",
              "healthStatus": "healthy",
              "features": ["transactional", "templates", "tracking"],
              "metrics": {
                "requestCount": 8750,
                "errorCount": 12,
                "errorRate": 0.0014,
                "avgResponseTime": "180ms",
                "uptime": "99.92%"
              }
            }
          ],
          "healthSummary": {
            "healthy": 8,
            "degraded": 1,
            "unhealthy": 0,
            "unknown": 0
          },
          "alerts": [
            {
              "integration": "twilio_sms",
              "level": "warning",
              "message": "Error rate above threshold (2.1%)",
              "timestamp": "2024-01-15T10:30:00Z"
            }
          ]
        }
      }
      """
    并且应该支持配置加密
    并且应该提供健康检查
    并且应该监控使用情况
    并且应该支持限流控制